package com.jeesite.modules.dataScreen.service;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.FIFOCache;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeesite.modules.dataScreen.constants.CacheConstants;
import com.jeesite.modules.dataScreen.dao.HotConcernDao;
import com.jeesite.modules.dataScreen.domain.alarm.AlarmFormCode;
import com.jeesite.modules.dataScreen.domain.alarm.AlarmFormDto;
import com.jeesite.modules.dataScreen.enums.CacheEnum;
import com.jeesite.modules.dataScreen.utils.ExecutorUtils;
import com.jeesite.modules.dataScreen.utils.MyDateUtils;
import com.jeesite.modules.dataScreen.web.vo.alarm.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 群众关注热点事项相关
 */
@Slf4j
@Service
public class HotConcernService {

    private static List<String> sxgcs = CollUtil.toList("投诉", "咨询", "求助");
    @Resource
    private HotConcernDao hotConcernDao;

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;


    //事项构成
    public Map<String, Integer> getItemConstitute() {
        Map<String, Integer> result = new HashMap<>();
        DateTime currentAt = DateUtil.date();
        List<AlarmFormDto> alarms = hotConcernDao.getAlarm(null, currentAt);
        if (CollUtil.isNotEmpty(alarms)) {
            Map<String, Integer> map = alarms.stream().collect(Collectors.toMap(e -> AlarmFormCode.toName(e.getCode()), AlarmFormDto::getNum));
            result.putAll(map);
        }
        List<AlarmFormDto> others = hotConcernDao.getAlarm12122(currentAt);
        others.addAll(hotConcernDao.getAlarm12345(currentAt));
        if (CollUtil.isNotEmpty(others)) {
            for (AlarmFormDto other : others) {
                String name = AlarmFormCode.toName(other.getCode());
                Integer defVal = result.getOrDefault(name, 0);
                result.put(name, defVal + other.getNum());
            }
        }
        Map<String, Integer> resultMap = new LinkedHashMap<>();
        for (String sxgc : sxgcs) {
            resultMap.put(sxgc, result.getOrDefault(sxgc, 0));
            result.remove(sxgc);
        }
        resultMap.put("其他", result.values().stream().mapToInt(Integer::intValue).sum());
        return resultMap;
    }

    //热点关注比率
    public AlarmRatioVo getRatio() {
        AlarmRatioVo ratioVo = new AlarmRatioVo();
        //办结率暂时固定100%
        ratioVo.setJbTotal(1L);
        ratioVo.setJbFinish(1L);
        //好差评
        long fineTotal = 0;
        long badTotal = 0;
        DateTime startTime = DateUtil.offsetDay(DateUtil.date(), -30);
        DateTime endTime = DateUtil.date();
        Long alarmCount = hotConcernDao.getAlarmCount(startTime, endTime, null);
        if (alarmCount != null) {
            fineTotal += alarmCount;
        }
        Map<String, Long> countMap = hotConcernDao.getAlarm12122CountMap(startTime, endTime);
        if (CollUtil.isNotEmpty(countMap)) {
            badTotal += countMap.getOrDefault("bad", 0L);
            fineTotal += countMap.getOrDefault("total", 0L);
        }
        Long alarm12345Count = hotConcernDao.getAlarm12345Count(startTime, endTime, null);
        if (alarm12345Count != null) {
            fineTotal += alarm12345Count;
        }
        ratioVo.setFineTotal(fineTotal);
        ratioVo.setBadTotal(badTotal);
        return ratioVo;
    }

    public HotConcernCurrentVo getHotConcernCurrent() {
        log.info("HotConcernCurrentVo查询数据库");
        HotConcernCurrentVo concernCurrentVo = new HotConcernCurrentVo();
        CountDownLatch countDownLatch = new CountDownLatch(3);
        AtomicLong startHotConcern = new AtomicLong(0);
        AtomicLong startTs = new AtomicLong(0);
        //获取前三分钟的量
        threadPoolExecutor.submit(() -> {
            try {
                DateTime startTime = DateUtil.beginOfDay(DateUtil.date());
                DateTime endTime = DateUtil.offsetMinute(DateUtil.date(), -6);
                startHotConcern.set(getHotConcernCount(startTime, endTime, null, null));
                startTs.set(getHotConcernCount(startTime, endTime, AlarmFormCode.TX.getCode(), AlarmFormCode.O_01.getCode()));
            } finally {
                countDownLatch.countDown();
            }
        });

        //当日数据
        AtomicLong hotConcernTotal = new AtomicLong(0);
        AtomicLong tsTotal = new AtomicLong(0);
        threadPoolExecutor.submit(() -> {
            try {
                DateTime startTime = DateUtil.beginOfDay(DateUtil.date());
                DateTime endTime = DateUtil.endOfDay(DateUtil.date());
                //总热点量
                hotConcernTotal.set(getHotConcernCount(startTime, endTime, null, null));
                tsTotal.set(getHotConcernCount(startTime, endTime, AlarmFormCode.TX.getCode(), AlarmFormCode.O_01.getCode()));

            } finally {
                countDownLatch.countDown();
            }
        });

        AtomicLong topHotConcernTotal = new AtomicLong(0);
        AtomicLong topTsTotal = new AtomicLong(0);
        threadPoolExecutor.submit(() -> {
            try {
                //环比
                DateTime startTime = DateUtil.beginOfDay(DateUtil.date());
                DateTime endTime = DateUtil.date();
                startTime = DateUtil.offsetDay(startTime, -1);
                endTime = DateUtil.offsetDay(endTime, -1);
                topHotConcernTotal.set(getHotConcernCount(startTime, endTime, null, null));
                topTsTotal.set(getHotConcernCount(startTime, endTime, AlarmFormCode.TX.getCode(), AlarmFormCode.O_01.getCode()));
            } finally {
                countDownLatch.countDown();
            }
        });
        try {
            countDownLatch.await(4, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        long tmp;
        if ((tmp = hotConcernTotal.get() - topHotConcernTotal.get()) != 0 && topHotConcernTotal.get() > 0) {
            BigDecimal divide = BigDecimal.valueOf(tmp * 100).divide(BigDecimal.valueOf(topHotConcernTotal.get()), BigDecimal.ROUND_DOWN, 0);
            if (divide.intValue() > -100) {
                concernCurrentVo.setTotalRatio(divide);
            }
        }
        if ((tmp = tsTotal.get() - topTsTotal.get()) != 0 && topTsTotal.get() > 0) {
            BigDecimal divide = BigDecimal.valueOf(tmp * 100).divide(BigDecimal.valueOf(topTsTotal.get()), BigDecimal.ROUND_DOWN, 0);
            if (divide.intValue() > -100) {
                concernCurrentVo.setComplainRatio(divide);
            }
        }
        Long[] topMonthAvgData = getTopMonthAvgData();
        concernCurrentVo.setTotal(startHotConcern.get());
        concernCurrentVo.setTopAvgTotal(topMonthAvgData[0]);
        concernCurrentVo.setComplain(startTs.get());
        concernCurrentVo.setTopAvgComplain(topMonthAvgData[1]);
        HotConcernCurrenCacheService.totalTimer.put(startHotConcern.get(), hotConcernTotal.get(), 180);
        HotConcernCurrenCacheService.tsTimer.put(startTs.get(), tsTotal.get(), 180);
        return concernCurrentVo;
    }

    private long getHotConcernCount(DateTime startTime, DateTime endTime, String alarmType, String otherType) {
        long result = 0L;
        Long alarmCount = hotConcernDao.getAlarmCount(startTime, endTime, alarmType);
        if (Objects.nonNull(alarmCount)) {
            result += alarmCount;
        }
        Long alarm12122Count = hotConcernDao.getAlarm12122Count(startTime, endTime, otherType);
        if (Objects.nonNull(alarm12122Count)) {
            result += alarm12122Count;
        }
//        Long alarm12345Count = hotConcernDao.getAlarm12345Count(startTime, endTime, otherType);
//        if (Objects.nonNull(alarm12345Count)) {
//            result += alarm12345Count;
//        }
        return result;
    }

    /**
     * 投诉/咨询情况
     *
     * @return ComplaintVo列表
     */
    public List<ComplaintConsultVo> getComplaintConsult(AlarmFormCode code, AlarmFormCode type) {
        List<ComplaintConsultVo> consultVos = hotConcernDao.getComplaintConsult(code.getCode(), type.getCode(), DateUtil.date());
        DateTime dateTime = DateUtil.offsetMonth(DateUtil.date(), -1);
        //上月多少天
        int month = DateUtil.lengthOfMonth(dateTime.month() + 1, dateTime.isLeapYear());
        Map<String, JSONObject> dataMap = hotConcernDao.getTopMonthDataMap(code.getCode(), type.getCode(), DateUtil.beginOfMonth(dateTime), DateUtil.endOfMonth(dateTime), DateUtil.date());
        for (ComplaintConsultVo consultVo : consultVos) {
            consultVo.setSameTimeLastWeek(0L);
            JSONObject jsonObject = dataMap.get(consultVo.getName());
            if (Objects.nonNull(jsonObject)) {
                consultVo.setSameTimeLastWeek((long) jsonObject.getIntValue("count") / month);
            }
        }
        return consultVos;
    }

    public Long[] getTopMonthAvgData() {
        DateTime dateTime = DateUtil.offsetMonth(DateUtil.date(), -1);
        //上月多少天
        int month = DateUtil.lengthOfMonth(dateTime.month() + 1, dateTime.isLeapYear());
        JSONObject dataMap = hotConcernDao.getTopMonthAvgData(DateUtil.beginOfMonth(dateTime), DateUtil.endOfMonth(dateTime), dateTime);
        long total = dataMap.getLongValue("total");
        long ts = dataMap.getLongValue("ts");
        return new Long[]{total / month, ts / month};
    }

    public List<FollowEventVo> getFollowEvent() {
        List<FollowEventVo> followEvents = hotConcernDao.getFollowEvent(DateUtil.date());
        //当月多少天
        int month = DateUtil.lengthOfMonth(1, DateUtil.offsetMonth(DateUtil.date(), -1).isLeapYear());
        DateTime dateTime = DateUtil.offsetMonth(DateUtil.date(), -1);
        Map<Integer, JSONObject> follwEventMap = hotConcernDao.getFollwEventMap(DateUtil.beginOfMonth(dateTime), DateUtil.endOfMonth(dateTime), DateUtil.date());
        for (FollowEventVo followEvent : followEvents) {
            followEvent.setHistoryNum(0L);
            JSONObject jsonObject = follwEventMap.get(Integer.valueOf(followEvent.getHours()));
            if (Objects.nonNull(jsonObject)) {
                followEvent.setHistoryNum((long) jsonObject.getIntValue("count") / month);
            }
        }
        return followEvents;
    }

    public List<EveryModuleVo> getEveryModule() {
        return hotConcernDao.getEveryModule(DateUtil.date());
    }

    public IPage<EveryModuleListVo> getEveryModuleList(Page<EveryModuleListVo> page, String acceptunit, String event, String overtime, Integer evaluate) {
        return getEveryModuleList(page, acceptunit, event, overtime, evaluate, DateUtil.date());
    }

    public IPage<EveryModuleListVo> getEveryModuleList(Page<EveryModuleListVo> page, String acceptunit, String event, String overtime, Integer evaluate, Date showData) {
        return hotConcernDao.getEveryModuleList(page, acceptunit, event, overtime, evaluate, showData, null, false);
    }

    public IPage<EveryModuleListVo> getEveryModuleList(Page<EveryModuleListVo> page, String acceptunit, String event, String overtime, Integer evaluate, Date showData, String orderId, boolean showAll) {
        return hotConcernDao.getEveryModuleList(page, acceptunit, event, overtime, evaluate, showData, orderId, showAll);
    }

    public Map<String, Object> enentEvaluateListPie(Integer type) {
        if (Objects.equals(type, 2)) {
            Map<String, Long> countMap = hotConcernDao.getAlarm12122CountMap(DateUtil.offsetDay(DateUtil.date(), -30), DateUtil.date());
            return Collections.singletonMap("高速", countMap.getOrDefault("bad", 0L));
        }
        List<JSONObject> jsonObjects = hotConcernDao.evaluateListPie(type, DateUtil.offsetDay(DateUtil.date(), -30), DateUtil.date());
        Map<String, Object> result = new HashMap<>();
        for (JSONObject jsonObject : jsonObjects) {
            result.put(jsonObject.getString("name"), jsonObject.get("count"));
        }
        return result;
    }

    /**
     * 投诉,咨询详情饼图
     *
     * @param pieType 1投诉，2咨询
     * @param name    公交,高速....
     */
    public List<JSONObject> getEveryPie(Integer pieType, String name) {
        String deptCode = getDeptCode(name);
        return hotConcernDao.getEveryPie(pieType, deptCode, DateUtil.date());
    }

    private String getDeptCode(String name) {
        switch (name) {
            case "公交":
                return "502600000000";
            case "轨道":
                return "502800000000";
            case "班线":
                return "502900000000";
            case "出租":
                return "502000000000";
            case "高速":
                return "高速";
        }
        return null;
    }

    public Map<String, BigDecimal> getItemConstitutePie() {
        Map<String, BigDecimal> map = new HashMap<>();
        List<EnentOvertimeListPieVo> list = hotConcernDao.getItemConstitutePie();
        BigDecimal total = new BigDecimal(list.stream().mapToInt(EnentOvertimeListPieVo::getEventNum).sum());
        list.forEach(item -> map.put(item.getName(), new BigDecimal(item.getEventNum()).divide(total, 4, RoundingMode.HALF_UP)));
        return map;
    }

    public Map<String, BigDecimal> getEventConstitutePie(String matter) {
        Map<String, BigDecimal> map = new HashMap<>();

        if ("投诉".equals(matter)) {
            List<EnentOvertimeListPieVo> list = hotConcernDao.getEventConstitutePie1();
            int num = hotConcernDao.getGaoSU1();
            EnentOvertimeListPieVo enentOvertimeListPieVo = new EnentOvertimeListPieVo();
            enentOvertimeListPieVo.setName("高速");
            enentOvertimeListPieVo.setEventNum(num);
            list.add(enentOvertimeListPieVo);

            list.forEach(item -> map.put(item.getName(), BigDecimal.valueOf(item.getEventNum())));

            return map;
        } else if ("咨询".equals(matter)) {
            List<EnentOvertimeListPieVo> list = hotConcernDao.getEventConstitutePie2();
            int num = hotConcernDao.getGaoSU2();
            EnentOvertimeListPieVo enentOvertimeListPieVo = new EnentOvertimeListPieVo();
            enentOvertimeListPieVo.setName("高速");
            enentOvertimeListPieVo.setEventNum(num);
            list.add(enentOvertimeListPieVo);
            list.forEach(item -> map.put(item.getName(), BigDecimal.valueOf(item.getEventNum())));

            return map;
        } else if ("求助".equals(matter)) {
            List<EnentOvertimeListPieVo> list = hotConcernDao.getEventConstitutePie3();
            int num = hotConcernDao.getGaoSU3();
            EnentOvertimeListPieVo enentOvertimeListPieVo = new EnentOvertimeListPieVo();
            enentOvertimeListPieVo.setName("高速");
            enentOvertimeListPieVo.setEventNum(num);
            list.add(enentOvertimeListPieVo);
            list.forEach(item -> map.put(item.getName(), BigDecimal.valueOf(item.getEventNum())));

            return map;
        }

        return map;
    }

    public Map<String, Integer> getGlItemConstitute() {
        Map<String, Integer> result = new HashMap<>();
        List<AlarmFormDto> alarms = hotConcernDao.getAlarm(CollUtil.toList("502900000000", "502500000000"), DateUtil.date());
        if (CollUtil.isNotEmpty(alarms)) {
            Map<String, Integer> map = alarms.stream().collect(Collectors.toMap(e -> AlarmFormCode.toName(e.getCode()), AlarmFormDto::getNum));
            result.putAll(map);
        }
        return result;
    }

    public List<EveryModuleDetailVo> detail(String myid, Integer detailType) {
        List<EveryModuleDetailVo> result = new ArrayList<>();
        if (!Objects.equals(detailType, 2)) {
            result = hotConcernDao.detail(myid, detailType);
        }
        if (CollUtil.isEmpty(result)) {

            EveryModuleDetailVo detailVo = new EveryModuleDetailVo();
            JSONObject object = hotConcernDao.getOneByIdAndType(myid, detailType);
            if (Objects.nonNull(object)) {
                detailVo.setDanwei(object.getString("danwei"));
                detailVo.setCreateTime(object.getString("createtime"));
                detailVo.setContent(object.getString("statusdesc"));
                detailVo.setStatus(object.getString("statusdesc"));
            }
            result.add(detailVo);
        }
        return result;
    }

}

